const os = require('os');
const ESLintWebpackPlugin = require('eslint-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path'); // nodejs 核心模块，专门用来处理路径问题
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
const ImageMinimizerPlugin = require('image-minimizer-webpack-plugin');
const PreloadWebpackPlugin = require('@vue/preload-webpack-plugin');
const WorkboxPlugin = require('workbox-webpack-plugin');

const threads = os.cpus().length; // cpu 核数

/**
 *  用来获取处理样式的 loader
 * @param {*} pre
 * @returns
 */
function getStyleLoader(pre) {
    return [
        //执行顺序：从右到左（从下到上）
        MiniCssExtractPlugin.loader, // 提取 css 成单独的文件
        'css-loader', //将css资源编译成commonjs的模块到js中
        {
            loader: 'postcss-loader',
            options: {
                postcssOptions: {
                    plugins: [
                        'postcss-preset-env', // 能解决大多数样式兼容性问题
                    ],
                },
            },
        },
        pre,
    ].filter(Boolean);
}

module.exports = {
    // 入口
    entry: './src/main.js',
    // 输出
    output: {
        // 所有文件的输出路径
        // __dirname nodejs 的变量，代表当前文件的文件夹目录
        path: path.resolve(__dirname, '../dist'),
        // 入口文件打包输出的文件名
        filename: 'static/js/[name].[contenthash:10].js',
        // 给打包输出的其他文件命名
        chunkFilename: 'static/js/[name].chunk.[contenthash:10].js',
        // 图片、字体等通过 type:asset 处理资源命名方式
        assetModuleFilename: 'static/media/[hash:10][ext][query]',
        // 自动清空上次打包结果
        // 原理：在打包前，将path整个目录内容清空，再进行打包
        clean: true,
    },
    // 加载器
    module: {
        rules: [
            // loader 的配置
            {
                oneOf: [
                    {
                        test: /\.css$/, // 只检测 .css 文件
                        use: getStyleLoader(),
                    },
                    {
                        test: /\.less$/,
                        // loader: 'xxx' 只能使用一个 loader
                        use: getStyleLoader('less-loader'),
                    },
                    {
                        test: /\.s[ac]ss$/,
                        // loader: 'xxx' 只能使用一个 loader
                        use: getStyleLoader('sass-loader'),
                    },
                    {
                        test: /\.styl$/,
                        use: getStyleLoader('stylus-loader'),
                    },
                    {
                        test: /\.(png|jpe?g|gif|webp|svg)$/,
                        type: 'asset',
                        parser: {
                            dataUrlCondition: {
                                // 小于 10 kb 的图片转base64
                                // 优点：减少请求数量   缺点：体积会更大
                                maxSize: 10 * 1024, //10kb
                            },
                        },
                        // generator: {
                        //     // 输出图片名称
                        //     // [hash:10] hash取值前10位
                        //     filename: 'static/images/[hash:10][ext][query]',
                        // },
                    },
                    {
                        test: /\.(ttf|woff2?|mp3|mp4|avi)$/,
                        type: 'asset/resource',
                        // generator: {
                        //     // 输出名称
                        //     filename: 'static/media/[hash:10][ext][query]',
                        // },
                    },
                    {
                        test: /\.js$/,
                        // exclude: /node_modules/, // 排除 node_modules 中的 js 文件（这些文件不处理）
                        include: path.resolve(__dirname, '../src'), // 只处理 src 下的文件，其他文件不处理
                        use: [
                            {
                                loader: 'thread-loader', // 开启多进程
                                options: {
                                    works: threads, // 进程数量
                                },
                            },
                            {
                                loader: 'babel-loader',
                                options: {
                                    // presets: ['@babel/preset-env'],
                                    cacheDirectory: true, // 开启 babel 缓存
                                    cacheCompression: false, // 关闭缓存文件压缩
                                    plugins: [
                                        '@babel/plugin-transform-runtime', //减少代码体积
                                    ],
                                },
                            },
                        ],
                    },
                ],
            },
        ],
    },
    // 插件
    plugins: [
        // plugin 的配置
        new ESLintWebpackPlugin({
            // 检测哪些文件
            context: path.resolve(__dirname, '../src'),
            exclude: 'node_modules', // 默认值
            cache: true, // 开启缓存
            cacheLocation: path.resolve(
                __dirname,
                '../node_modules/.cache/eslintcache'
            ),
            threads, // 开启多进程和设置进程数量
        }),
        new HtmlWebpackPlugin({
            // 模板：以 public/index.html 文件创建新的 html 文件
            // 新的文件特点：1. 结构和原来一致 2.自动引入打包输出的资源
            template: path.resolve(__dirname, '../public/index.html'),
        }),
        new MiniCssExtractPlugin({
            filename: 'static/css/[name].[contenthash:10].css',
            chunkFilename: 'static/css/[name].chunk.[contenthash:10].css',
        }),
        // new CssMinimizerPlugin(),
        // new TerserWebpackPlugin({
        //     parallel: threads, // 开启多进程和设置进程数量
        // }),
        new PreloadWebpackPlugin({
            // rel: 'preload',
            // as: 'script',
            rel: 'prefetch',
        }),
        new WorkboxPlugin.GenerateSW({
            // 这些选项帮助快速启用 ServiceWorkers
            // 不允许遗留任何“旧的” ServiceWorkers
            clientsClaim: true,
            skipWaiting: true,
        }),
    ],
    optimization: {
        // 压缩的操作
        minimizer: [
            // 压缩 css
            new CssMinimizerPlugin(),
            // 压缩 js
            new TerserWebpackPlugin({
                parallel: threads, // 开启多进程和设置进程数量
            }),
            // 压缩图片
            new ImageMinimizerPlugin({
                minimizer: {
                    implementation: ImageMinimizerPlugin.imageminGenerate,
                    options: {
                        plugins: [
                            ['gifsicle', { interlaced: true }],
                            ['jpegtran', { progressive: true }],
                            ['optipng', { optimizationLevel: 5 }],
                            [
                                'svgo',
                                {
                                    plugins: [
                                        'preset-default',
                                        'prefixId',
                                        {
                                            name: 'sortAttrs',
                                            params: {
                                                xmlnsOrder: 'alphabetical',
                                            },
                                        },
                                    ],
                                },
                            ],
                        ],
                    },
                },
            }),
        ],
        // 代码分割配置
        splitChunks: {
            chunks: 'all',
            // 其他都用默认值
        },
        runtimeChunk: {
            name: (entrypoint) => `runtime~${entrypoint.name}.js`,
        },
    },
    // 模式
    mode: 'production',
    devtool: 'source-map',
};
